/**
 * @typedef {Object} RemainingTime
 * @property {number} workdays - 剩余工作日数（可为负数，表示超时）
 * @property {number} totalDays - 总剩余天数（可为负数）
 * @property {number} hours - 剩余小时数（可为负数）
 * @property {number} minutes - 剩余分钟数（可为负数）
 */

/**
 * @typedef {Object} WarningResult
 * @property {boolean} shouldTrigger - 是否触发预警（超时或剩余工作日≤阈值）
 * @property {RemainingTime} remainingTime - 剩余时间详情
 */

/**
 * 将日期格式化为 YYYY-MM-DD
 * @param {Date} date - 要格式化的日期
 * @returns {string} 格式化的日期字符串
 */
function formatDate(date) {
  return date.toISOString().split('T')[0];
}

/**
 * 检查日期是否为节假日
 * @param {Date} date - 要检查的日期
 * @param {Set<string>} holidays - 节假日日期集合（YYYY-MM-DD 格式）
 * @returns {boolean} 是否为节假日
 */
function isHoliday(date, holidays) {
  return holidays.has(formatDate(date));
}

/**
 * 检查日期是否为工作日（周一至周五，非节假日）
 * @param {Date} date - 要检查的日期
 * @param {Set<string>} holidays - 节假日集合
 * @returns {boolean} 是否为工作日
 */
function isWorkday(date, holidays) {
  const dayOfWeek = date.getDay();
  return dayOfWeek !== 0 && dayOfWeek !== 6 && !isHoliday(date, holidays);
}

/**
 * 估算日期范围内的工作日数，优化迭代
 * @param {Date} startDate - 开始日期
 * @param {Date} endDate - 结束日期
 * @returns {number} 近似工作日数
 */
function estimateWorkdays(startDate, endDate) {
  const msPerDay = 1000 * 60 * 60 * 24;
  const totalDays = Math.ceil((endDate - startDate) / msPerDay);
  return Math.floor((totalDays * 5) / 7); // 每7天约5个工作日
}

/**
 * 在开始日期后添加指定工作日数，保留时间
 * @param {Date} startDate - 开始日期
 * @param {number} workdays - 要添加的工作日数
 * @param {Set<string>} holidays - 节假日集合
 * @returns {Date} 结果日期
 */
function addWorkdays(startDate, workdays, holidays) {
  if (workdays <= 0) return new Date(startDate);

  let current = new Date(startDate);
  let remainingWorkdays = workdays;

  // 估算所需总天数
  const estimatedDays = Math.ceil((workdays * 7) / 5);
  current.setDate(current.getDate() + estimatedDays);

  // 精确调整
  while (remainingWorkdays > 0) {
    current.setDate(current.getDate() - 1);
    if (isWorkday(current, holidays)) remainingWorkdays++;
    current.setDate(current.getDate() + 1);
    if (isWorkday(current, holidays)) remainingWorkdays--;
  }

  return current;
}

/**
 * 计算两个日期之间的剩余时间（支持超时负值）
 * @param {Date} startDate - 开始日期
 * @param {Date} endDate - 结束日期
 * @param {Set<string>} holidays - 节假日集合
 * @returns {RemainingTime} 剩余时间对象
 */
function getRemainingTime(startDate, endDate, holidays) {
  const msPerDay = 1000 * 60 * 60 * 24;
  const diffMs = endDate - startDate;
  const isOverdue = diffMs < 0;

  // 计算总时间差
  const absDiffMs = Math.abs(diffMs);
  const totalDays = Math.floor(absDiffMs / msPerDay);
  const hours = Math.floor((absDiffMs % msPerDay) / (1000 * 60 * 60));
  const minutes = Math.floor((absDiffMs % (1000 * 60 * 60)) / (1000 * 60));

  // 计算工作日
  let workdays = 0;
  let current = new Date(isOverdue ? endDate : startDate);
  current.setHours(0, 0, 0, 0);
  const target = new Date(isOverdue ? startDate : endDate);
  target.setHours(0, 0, 0, 0);

  const estimatedWorkdays = estimateWorkdays(current, target);
  if (estimatedWorkdays > 0) {
    current.setDate(current.getDate() + Math.floor((estimatedWorkdays * 7) / 5));
  }

  while (current <= target) {
    if (isWorkday(current, holidays)) workdays++;
    current.setDate(current.getDate() + 1);
  }

  // 如果超时，工作日数取负值
  workdays = isOverdue ? -workdays : workdays;
  return {
    workdays,
    totalDays: isOverdue ? -totalDays : totalDays,
    hours: isOverdue ? -hours : hours,
    minutes: isOverdue ? -minutes : minutes,
  };
}

/**
 * 判断是否触发工单预警
 * @param {string|Date} startTime - 流程开始时间（ISO字符串或 Date 对象）
 * @param {string} status - 工单状态
 * @param {number} workdaysLimit - 流程办理工作日限额
 * @param {number} warningThreshold - 触发预警的剩余工作日阈值
 * @param {Date} [currentTime] - 当前时间（可选，默认当前时间）
 * @param {string[]} [holidays] - 节假日数组（YYYY-MM-DD 格式，可选）
 * @returns {WarningResult} 预警结果和剩余时间
 */
function triggerWarning(startTime, status, workdaysLimit, warningThreshold, currentTime = new Date(), holidays = []) {
  // 默认节假日（2025年部分节假日，可替换）
  const defaultHolidays = [
    '2025-01-01', // 元旦
    '2025-01-29', '2025-01-30', '2025-01-31', // 春节
    '2025-04-05', // 清明节
    '2025-05-01', // 劳动节
    '2025-06-02', // 端午节
    '2025-09-09', // 中秋节
    '2025-10-01', '2025-10-02', '2025-10-03', // 国庆节
  ];

  // 转换为 Set 优化查找
  const holidayList = new Set(holidays.length > 0 ? holidays : defaultHolidays);

  // 验证 startTime
  const startDate = new Date(startTime);
  if (isNaN(startDate)) {
    console.error('无效的 startTime 格式');
    return { shouldTrigger: false, remainingTime: { workdays: 0, totalDays: 0, hours: 0, minutes: 0 } };
  }

  // 检查工单状态
  if (status !== '在途') {
    return { shouldTrigger: false, remainingTime: { workdays: 0, totalDays: 0, hours: 0, minutes: 0 } };
  }

  // 验证 workdaysLimit 和 warningThreshold
  if (!Number.isInteger(workdaysLimit) || workdaysLimit < 0) {
    console.error('无效的 workdaysLimit');
    return { shouldTrigger: false, remainingTime: { workdays: 0, totalDays: 0, hours: 0, minutes: 0 } };
  }
  if (!Number.isInteger(warningThreshold) || warningThreshold < 0) {
    console.error('无效的 warningThreshold');
    return { shouldTrigger: false, remainingTime: { workdays: 0, totalDays: 0, hours: 0, minutes: 0 } };
  }

  // 计算截止日期
  const deadline = addWorkdays(startDate, workdaysLimit, holidayList);

  // 计算剩余时间
  const remainingTime = getRemainingTime(currentTime, deadline, holidayList);

  // 触发预警：剩余工作日≤阈值 或已超时
  const shouldTrigger = remainingTime.workdays <= warningThreshold;

  return { shouldTrigger, remainingTime };
}

// 示例用法
// const start = new Date('2025-01-10T09:15:30');
// const holidays = ['2025-01-29', '2025-01-30'];
// console.log(triggerWarning(start, '在途', 15, 3, new Date('2025-02-10T12:30:45'), holidays));

export { triggerWarning }